/*******************************************************************************
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*******************************************************************************/
package org.apache.ofbiz.entity.transaction;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.concurrent.ConcurrentHashMap;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import javax.sql.XAConnection;
import javax.sql.XADataSource;
import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;
import org.apache.ofbiz.base.config.GenericConfigException;
import org.apache.ofbiz.base.util.Debug;
import org.apache.ofbiz.base.util.GeneralException;
import org.apache.ofbiz.base.util.JNDIContextFactory;
import org.apache.ofbiz.base.util.UtilValidate;
import org.apache.ofbiz.entity.GenericEntityException;
import org.apache.ofbiz.entity.config.model.*;
import org.apache.ofbiz.entity.datasource.GenericHelperInfo;
import org.apache.ofbiz.entity.jdbc.ConnectionFactoryLoader;
/**
* Central source for Tyrex JTA objects from JNDI
*/
public class JNDITransactionFactory implements TransactionFactory {
// Debug module name
public static final String module = JNDITransactionFactory.class.getName();
static TransactionManager transactionManager = null;
static UserTransaction userTransaction = null;
// protected static UtilCache dsCache = new UtilCache("entity.JndiDataSources", 0, 0);
protected static ConcurrentHashMap<String, DataSource> dsCache = new ConcurrentHashMap<String, DataSource>();
public TransactionManager getTransactionManager() {
if (transactionManager == null) {
synchronized (JNDITransactionFactory.class) {
// try again inside the synch just in case someone when through while we were waiting
if (transactionManager == null) {
try {
String jndiName = EntityConfig.getInstance().getTransactionFactory().getTransactionManagerJndi().getJndiName();
String jndiServerName = EntityConfig.getInstance().getTransactionFactory().getTransactionManagerJndi().getJndiServerName();
if (UtilValidate.isNotEmpty(jndiName)) {
// if (Debug.verboseOn()) Debug.logVerbose("[JNDITransactionFactory.getTransactionManager] Trying JNDI name " + jndiName, module);
try {
InitialContext ic = JNDIContextFactory.getInitialContext(jndiServerName);
if (ic != null) {
transactionManager = (TransactionManager) ic.lookup(jndiName);
}
} catch (NamingException ne) {
Debug.logWarning(ne, "NamingException while finding TransactionManager named " + jndiName + " in JNDI.", module);
transactionManager = null;
}
if (transactionManager == null) {
Debug.logWarning("Failed to find TransactionManager named " + jndiName + " in JNDI.", module);
}
}
} catch (GeneralException e) {
Debug.logError(e, module);
transactionManager = null;
}
}
}
}
return transactionManager;
}
public UserTransaction getUserTransaction() {
if (userTransaction == null) {
synchronized (JNDITransactionFactory.class) {
// try again inside the synch just in case someone when through while we were waiting
if (userTransaction == null) {
try {
String jndiName = EntityConfig.getInstance().getTransactionFactory().getUserTransactionJndi().getJndiName();
String jndiServerName = EntityConfig.getInstance().getTransactionFactory().getUserTransactionJndi().getJndiServerName();
if (UtilValidate.isNotEmpty(jndiName)) {
try {
InitialContext ic = JNDIContextFactory.getInitialContext(jndiServerName);
if (ic != null) {
userTransaction = (UserTransaction) ic.lookup(jndiName);
}
} catch (NamingException ne) {
Debug.logWarning(ne, "NamingException while finding UserTransaction named " + jndiName + " in JNDI.", module);
userTransaction = null;
}
if (userTransaction == null) {
Debug.logWarning("Failed to find UserTransaction named " + jndiName + " in JNDI.", module);
}
}
} catch (GeneralException e) {
Debug.logError(e, module);
transactionManager = null;
}
}
}
}
return userTransaction;
}
public String getTxMgrName() {
return "jndi";
}
public Connection getConnection(GenericHelperInfo helperInfo) throws SQLException, GenericEntityException {
Datasource datasourceInfo = EntityConfig.getDatasource(helperInfo.getHelperBaseName());
if (datasourceInfo.getJndiJdbc() != null) {
JndiJdbc jndiJdbcElement = datasourceInfo.getJndiJdbc();
String jndiName = jndiJdbcElement.getJndiName();
String jndiServerName = jndiJdbcElement.getJndiServerName();
Connection con = getJndiConnection(jndiName, jndiServerName);
if (con != null) return TransactionUtil.getCursorConnection(helperInfo, con);
} else {
// Debug.logError("JNDI loaded is the configured transaction manager but no jndi-jdbc element was specified in the " + helperName + " datasource. Please check your configuration.", module);
}
if (datasourceInfo.getInlineJdbc() != null) {
Connection otherCon = ConnectionFactoryLoader.getInstance().getConnection(helperInfo, datasourceInfo.getInlineJdbc());
return TransactionUtil.getCursorConnection(helperInfo, otherCon);
} else {
//no real need to print an error here
return null;
}
}
public static Connection getJndiConnection(String jndiName, String jndiServerName) throws SQLException, GenericEntityException {
// if (Debug.verboseOn()) Debug.logVerbose("Trying JNDI name " + jndiName, module);
DataSource ds = dsCache.get(jndiName);
if (ds != null) {
if (ds instanceof XADataSource) {
XADataSource xads = (XADataSource) ds;
return TransactionUtil.enlistConnection(xads.getXAConnection());
} else {
return ds.getConnection();
}
}
try {
if (Debug.infoOn())
Debug.logInfo("Doing JNDI lookup for name " + jndiName, module);
InitialContext ic = JNDIContextFactory.getInitialContext(jndiServerName);
if (ic != null) {
ds = (DataSource) ic.lookup(jndiName);
} else {
Debug.logWarning("Initial Context returned was NULL for server name " + jndiServerName, module);
}
if (ds != null) {
if (Debug.verboseOn())
Debug.logVerbose("Got a Datasource object.", module);
dsCache.putIfAbsent(jndiName, ds);
ds = dsCache.get(jndiName);
Connection con;
if (ds instanceof XADataSource) {
if (Debug.infoOn())
Debug.logInfo("Got XADataSource for name " + jndiName, module);
XADataSource xads = (XADataSource) ds;
XAConnection xac = xads.getXAConnection();
con = TransactionUtil.enlistConnection(xac);
} else {
if (Debug.infoOn())
Debug.logInfo("Got DataSource for name " + jndiName, module);
con = ds.getConnection();
}
return con;
} else {
Debug.logError("Datasource returned was NULL.", module);
}
} catch (NamingException ne) {
Debug.logWarning(ne, "Failed to find DataSource named " + jndiName + " in JNDI server with name " + jndiServerName + ". Trying normal database.", module);
} catch (GenericConfigException gce) {
throw new GenericEntityException("Problems with the JNDI configuration.", gce.getNested());
}
return null;
}
public void shutdown() {}
}